﻿#include "Client.CMain.h"
#include "../Settings.h"
#include "../../Shared/Language.h"
#include "../MirGraphics/DXManager.h"
#include "../MirSounds/SoundManager.h"
#include "../MirScenes/GameScene.h"
#include "../MirControls/MirScene.h"
#include "../Program.h"
#include "../MirControls/MirTextBox.h"
#include "../MirNetwork/Network.h"
#include "../MirControls/MirAnimatedControl.h"
#include "../MirControls/MirAnimatedButton.h"
#include "../MirObjects/MapObject.h"
#include "../../Shared/Functions/Functions.h"

using namespace Client::MirControls;
using namespace Client::MirGraphics;
using namespace Client::MirNetwork;
using namespace Client::MirScenes;
using namespace Client::MirSounds;
using namespace SlimDX::Direct3D9;
using namespace SlimDX::Windows;

namespace Client
{

MirControl *CMain::DebugBaseLabel;
MirControl *CMain::HintBaseLabel;
MirLabel *CMain::DebugTextLabel;
MirLabel *CMain::HintTextLabel;
MirLabel *CMain::ScreenshotTextLabel;
CMain::Graphics *Graphics;
Point *CMain::MPoint;
Stopwatch *const CMain::Timer = Stopwatch::StartNew();
const DateTime CMain::StartTime = DateTime::Now;
long long CMain::Time = 0;
long long CMain::OldTime = 0;

    DateTime CMain::getNow()
    {
        return StartTime.AddMilliseconds(Time);
    }

CMain::Random *const Random = new Random();
std::string CMain::DebugText = "";
long long CMain::_fpsTime = 0;
int CMain::_fps = 0;
int CMain::FPS = 0;
long long CMain::PingTime = 0;
long long CMain::NextPing = 10000;
bool CMain::Shift = false;
bool CMain::Alt = false;
bool CMain::Ctrl = false;
bool CMain::Tilde = false;
double CMain::BytesSent = 0;
double CMain::BytesReceived = 0;
KeyBindSettings *CMain::InputKeys = new KeyBindSettings();

    CMain::CMain()
    {
        InitializeComponent();

        Application::Idle += Application_Idle;

        MouseClick += CMain_MouseClick;
        MouseDown += CMain_MouseDown;
        MouseUp += CMain_MouseUp;
        MouseMove += CMain_MouseMove;
        MouseDoubleClick += CMain_MouseDoubleClick;
        KeyPress += CMain_KeyPress;
        KeyDown += CMain_KeyDown;
        KeyUp += CMain_KeyUp;
        Deactivate += CMain_Deactivate;
        MouseWheel += CMain_MouseWheel;


        SetStyle(ControlStyles::AllPaintingInWmPaint | ControlStyles::UserPaint | ControlStyles::Selectable, true);
        FormBorderStyle = Settings::FullScreen ? FormBorderStyle::None : FormBorderStyle::FixedDialog;

        Graphics = CreateGraphics();
        Graphics->SmoothingMode = SmoothingMode::AntiAlias;
        Graphics->TextRenderingHint = TextRenderingHint::AntiAliasGridFit;
        Graphics->CompositingQuality = CompositingQuality::HighQuality;
        Graphics->InterpolationMode = InterpolationMode::NearestNeighbor;
        Graphics->PixelOffsetMode = PixelOffsetMode::HighQuality;
        Graphics->TextContrast = 0;
    }

    void CMain::CMain_Load(std::any sender, EventArgs *e)
    {
        this->Text = GameLanguage::GameName;
        try
        {
            ClientSize = new Size(Settings::ScreenWidth, Settings::ScreenHeight);

            LoadMouseCursors();
            SetMouseCursor(MouseCursor::Default);

            DXManager::Create();
            SoundManager::Create();
            CenterToScreen();
        }
        catch (const std::runtime_error &ex)
        {
            SaveError(ex.what());
        }
    }

    void CMain::Application_Idle(std::any sender, EventArgs *e)
    {
        try
        {
            while (getAppStillIdle())
            {
                UpdateTime();
                UpdateEnviroment();
                RenderEnvironment();
            }

        }
        catch (const std::runtime_error &ex)
        {
            SaveError(ex.what());
        }
    }

    void CMain::CMain_Deactivate(std::any sender, EventArgs *e)
    {
        MapControl::MapButtons = MouseButtons::None;
        Shift = false;
        Alt = false;
        Ctrl = false;
        Tilde = false;
    }

    void CMain::CMain_KeyDown(std::any sender, KeyEventArgs *e)
    {
        Shift = e->Shift;
        Alt = e->Alt;
        Ctrl = e->Control;

        if (e->KeyCode == Keys->Oem8)
        {
            CMain::Tilde = true;
        }

        try
        {
            if (e->Alt && e->KeyCode == Keys->Enter)
            {
                ToggleFullScreen();
                return;
            }

            if (MirScene::ActiveScene != nullptr)
            {
                MirScene::ActiveScene->OnKeyDown(e);
            }

        }
        catch (const std::runtime_error &ex)
        {
            SaveError(ex.what());
        }
    }

    void CMain::CMain_MouseMove(std::any sender, MouseEventArgs *e)
    {
        if (Settings::FullScreen)
        {
            Cursor->Clip = new Rectangle(0, 0, Settings::ScreenWidth, Settings::ScreenHeight);
        }

        MPoint = Program::Form->PointToClient(Cursor::Position);

        try
        {
            if (MirScene::ActiveScene != nullptr)
            {
                MirScene::ActiveScene->OnMouseMove(e);
            }
        }
        catch (const std::runtime_error &ex)
        {
            SaveError(ex.what());
        }
    }

    void CMain::CMain_KeyUp(std::any sender, KeyEventArgs *e)
    {
        Shift = e->Shift;
        Alt = e->Alt;
        Ctrl = e->Control;

        if (e->KeyCode == Keys->Oem8)
        {
            CMain::Tilde = false;
        }

        for (auto KeyCheck : CMain::InputKeys->Keylist)
        {
            if (KeyCheck->function != KeybindOptions::Screenshot)
            {
                continue;
            }
            if (KeyCheck->Key != e->KeyCode)
            {
                continue;
            }
            if ((KeyCheck->RequireAlt != 2) && (KeyCheck->RequireAlt != (Alt ? 1 : 0)))
            {
                continue;
            }
            if ((KeyCheck->RequireShift != 2) && (KeyCheck->RequireShift != (Shift ? 1 : 0)))
            {
                continue;
            }
            if ((KeyCheck->RequireCtrl != 2) && (KeyCheck->RequireCtrl != (Ctrl ? 1 : 0)))
            {
                continue;
            }
            if ((KeyCheck->RequireTilde != 2) && (KeyCheck->RequireTilde != (Tilde ? 1 : 0)))
            {
                continue;
            }
            Program::Form->CreateScreenShot();
            break;

        }
        try
        {
            if (MirScene::ActiveScene != nullptr)
            {
                MirScene::ActiveScene->OnKeyUp(e);
            }
        }
        catch (const std::runtime_error &ex)
        {
            SaveError(ex.what());
        }
    }

    void CMain::CMain_KeyPress(std::any sender, KeyPressEventArgs *e)
    {
        try
        {
            if (MirScene::ActiveScene != nullptr)
            {
                MirScene::ActiveScene->OnKeyPress(e);
            }
        }
        catch (const std::runtime_error &ex)
        {
            SaveError(ex.what());
        }
    }

    void CMain::CMain_MouseDoubleClick(std::any sender, MouseEventArgs *e)
    {
        try
        {
            if (MirScene::ActiveScene != nullptr)
            {
                MirScene::ActiveScene->OnMouseClick(e);
            }
        }
        catch (const std::runtime_error &ex)
        {
            SaveError(ex.what());
        }
    }

    void CMain::CMain_MouseUp(std::any sender, MouseEventArgs *e)
    {
        MapControl::MapButtons &= ~e->Button;
        if (!MapControl::MapButtons->HasFlag(MouseButtons::Right))
        {
            GameScene::CanRun = false;
        }

        try
        {
            if (MirScene::ActiveScene != nullptr)
            {
                MirScene::ActiveScene->OnMouseUp(e);
            }
        }
        catch (const std::runtime_error &ex)
        {
            SaveError(ex.what());
        }
    }

    void CMain::CMain_MouseDown(std::any sender, MouseEventArgs *e)
    {
        if (dynamic_cast<TextBox*>(Program::Form->ActiveControl) != nullptr)
        {
            MirTextBox *textBox = dynamic_cast<MirTextBox*>(Program::Form->ActiveControl->Tag);

            if (textBox != nullptr && textBox->CanLoseFocus)
            {
                Program::Form->ActiveControl = nullptr;
            }
        }

        if (e->Button == MouseButtons::Right && (GameScene::SelectedCell != nullptr || GameScene::PickedUpGold))
        {
            GameScene::SelectedCell = nullptr;
            GameScene::PickedUpGold = false;
            return;
        }

        try
        {
            if (MirScene::ActiveScene != nullptr)
            {
                MirScene::ActiveScene->OnMouseDown(e);
            }
        }
        catch (const std::runtime_error &ex)
        {
            SaveError(ex.what());
        }
    }

    void CMain::CMain_MouseClick(std::any sender, MouseEventArgs *e)
    {
        try
        {
            if (MirScene::ActiveScene != nullptr)
            {
                MirScene::ActiveScene->OnMouseClick(e);
            }
        }
        catch (const std::runtime_error &ex)
        {
            SaveError(ex.what());
        }
    }

    void CMain::CMain_MouseWheel(std::any sender, MouseEventArgs *e)
    {
        try
        {
            if (MirScene::ActiveScene != nullptr)
            {
                MirScene::ActiveScene->OnMouseWheel(e);
            }
        }
        catch (const std::runtime_error &ex)
        {
            SaveError(ex.what());
        }
    }

    void CMain::UpdateTime()
    {
        Time = Timer->ElapsedMilliseconds;
    }

    void CMain::UpdateEnviroment()
    {

        if (Time >= _fpsTime)
        {
            _fpsTime = Time + 1000;
            FPS = _fps;
            _fps = 0;
            DXManager::Clean(); // Clean once a second.
        }
        else
        {
            _fps++;
        }

        Network::Process();

        if (MirScene::ActiveScene != nullptr)
        {
            MirScene::ActiveScene->Process();
        }

        for (int i = 0; i < MirAnimatedControl::Animations.size(); i++)
        {
            MirAnimatedControl::Animations[i]->UpdateOffSet();
        }

        for (int i = 0; i < MirAnimatedButton::Animations.size(); i++)
        {
            MirAnimatedButton::Animations[i]->UpdateOffSet();
        }

        CreateHintLabel();

        if (Settings::DebugMode)
        {
            CreateDebugLabel();
        }
    }

    void CMain::RenderEnvironment()
    {
        try
        {
            if (DXManager::DeviceLost)
            {
                DXManager::AttemptReset();
                delay(1);
                return;
            }

            DXManager::Device->Clear(ClearFlags::Target, Color::CornflowerBlue, 0, 0);
            DXManager::Device->BeginScene();
            DXManager::Sprite->Begin(SpriteFlags::AlphaBlend);
            DXManager::SetSurface(DXManager::MainSurface);

            if (MirScene::ActiveScene != nullptr)
            {
                MirScene::ActiveScene->Draw();
            }

            DXManager::Sprite->End();
            DXManager::Device->EndScene();
            DXManager::Device->Present();
        }
        catch (const Direct3D9Exception &ex)
        {
            DXManager::DeviceLost = true;
        }
        catch (const std::runtime_error &ex)
        {
            SaveError(ex.what());

            DXManager::AttemptRecovery();
        }
    }

    void CMain::CreateDebugLabel()
    {
        std::string text;

        if (MirControl::MouseControl != nullptr)
        {
            text = StringHelper::formatSimple("FPS: {0}", FPS);

            if (dynamic_cast<MapControl*>(MirControl::MouseControl) != nullptr)
            {
                text += StringHelper::formatSimple(", Co Ords: {0}", MapControl::getMapLocation());
            }

            if (dynamic_cast<GameScene*>(MirScene::ActiveScene) != nullptr)
            {
                text += StringHelper::formatSimple(", Objects: {0}", MapControl::Objects.size());
            }

            if (dynamic_cast<GameScene*>(MirScene::ActiveScene) != nullptr && !DebugText.empty())
            {
                text += StringHelper::formatSimple(", Debug: {0}", DebugText);
            }

            if (MirObjects::MapObject::MouseObject != nullptr)
            {
                text += StringHelper::formatSimple(", Target: {0}", MirObjects::MapObject::MouseObject->Name);
            }
            else
            {
                text += std::string::Format(", Target: none");
            }
        }
        else
        {
            text = StringHelper::formatSimple("FPS: {0}", FPS);
        }

        text += StringHelper::formatSimple(", Ping: {0}", PingTime);

        text += StringHelper::formatSimple(", Sent: {0}, Received: {1}", Functions::ConvertByteSize(BytesSent), Functions::ConvertByteSize(BytesReceived));

        text += StringHelper::formatSimple(", TLC: {0}", DXManager::TextureList.size()([&] (std::any x)
        {
            x::TextureValid;
        }));
        text += StringHelper::formatSimple(", CLC: {0}", DXManager::ControlList.size()([&] (std::any x)
        {
            return x->IsDisposed == false;
        }));

        if (Settings::FullScreen)
        {
            if (DebugBaseLabel == nullptr || DebugBaseLabel->isDisposed())
            {
                DebugBaseLabel = new MirControl();
                DebugBaseLabel->setBackColour(Color::FromArgb(50, 50, 50));
                DebugBaseLabel->setBorder(true);
                DebugBaseLabel->setBorderColour(Color::Black);
                DebugBaseLabel->setDrawControlTexture(true);
                Point tempVar(5, 5);
                DebugBaseLabel->setLocation(&tempVar);
                DebugBaseLabel->setNotControl(true);
                DebugBaseLabel->setOpacity(0.5F);
            }

            if (DebugTextLabel == nullptr || DebugTextLabel->isDisposed())
            {
                DebugTextLabel = new MirLabel();
                DebugTextLabel->setAutoSize(true);
                DebugTextLabel->setBackColour(Color::Transparent);
                DebugTextLabel->setForeColour(Color::White);
                DebugTextLabel->setParent(DebugBaseLabel);

                DebugTextLabel->SizeChanged->addListener([&] (o, e)
                {
                    DebugBaseLabel->setSize(DebugTextLabel->getSize());
                });
            }

            DebugTextLabel->setText(text);
        }
        else
        {
            if (DebugBaseLabel != nullptr && DebugBaseLabel->isDisposed() == false)
            {
                DebugBaseLabel->Dispose();
                DebugBaseLabel = nullptr;
            }
            if (DebugTextLabel != nullptr && DebugTextLabel->isDisposed() == false)
            {
                DebugTextLabel->Dispose();
                DebugTextLabel = nullptr;
            }

            Program::Form->Text = StringHelper::formatSimple("{0} - {1}", GameLanguage::GameName, text);
        }
    }

    void CMain::CreateHintLabel()
    {
        if (HintBaseLabel == nullptr || HintBaseLabel->isDisposed())
        {
            HintBaseLabel = new MirControl();
            HintBaseLabel->setBackColour(Color::FromArgb(128, 128, 50));
            HintBaseLabel->setBorder(true);
            HintBaseLabel->setDrawControlTexture(true);
            HintBaseLabel->setBorderColour(Color::Yellow);
            HintBaseLabel->setForeColour(Color::Yellow);
            HintBaseLabel->setParent(MirScene::ActiveScene);
            HintBaseLabel->setNotControl(true);
            HintBaseLabel->setOpacity(0.5F);
        }


        if (HintTextLabel == nullptr || HintTextLabel->isDisposed())
        {
            HintTextLabel = new MirLabel();
            HintTextLabel->setAutoSize(true);
            HintTextLabel->setBackColour(Color::Transparent);
            HintTextLabel->setForeColour(Color::White);
            HintTextLabel->setParent(HintBaseLabel);

            HintTextLabel->SizeChanged->addListener([&] (o, e)
            {
                HintBaseLabel->setSize(HintTextLabel->getSize());
            });
        }

        if (MirControl::MouseControl == nullptr || MirControl::MouseControl->getHint().empty())
        {
            HintBaseLabel->setVisible(false);
            return;
        }

        HintBaseLabel->setVisible(true);

        HintTextLabel->setText(MirControl::MouseControl->getHint());

        Point *point = Functions::Add(MPoint, -HintTextLabel->getSize()->Width, 20);

        if (point->X + HintBaseLabel->getSize()->Width >= Settings::ScreenWidth)
        {
            point->X = Settings::ScreenWidth - HintBaseLabel->getSize()->Width - 1;
        }
        if (point->Y + HintBaseLabel->getSize()->Height >= Settings::ScreenHeight)
        {
            point->Y = Settings::ScreenHeight - HintBaseLabel->getSize()->Height - 1;
        }

        if (point->X < 0)
        {
            point->X = 0;
        }
        if (point->Y < 0)
        {
            point->Y = 0;
        }

        HintBaseLabel->setLocation(point);
    }

    void CMain::ToggleFullScreen()
    {
        Settings::FullScreen = !Settings::FullScreen;

        Program::Form->FormBorderStyle = Settings::FullScreen ? FormBorderStyle::None : FormBorderStyle::FixedDialog;

        DXManager::Parameters->Windowed = !Settings::FullScreen;

        Program::Form->ClientSize = new Size(Settings::ScreenWidth, Settings::ScreenHeight);

        DXManager::ResetDevice();

        if (MirScene::ActiveScene == GameScene::Scene)
        {
            GameScene::Scene->MapControl->FloorValid = false;
            GameScene::Scene->TextureValid = false;
        }

        Program::Form->CenterToScreen();
    }

    void CMain::CreateScreenShot()
    {
        std::string text = std::string::Format("[{0} Server {1}] {2} {3:hh\\:mm\\:ss}", Settings::P_ServerName.length() > 0 ? Settings::P_ServerName : "Crystal", MapControl::getUser() != nullptr ? MapControl::getUser()->Name : "", getNow().ToShortDateString(), getNow().TimeOfDay);

        Surface *backbuffer = DXManager::Device->GetBackBuffer(0, 0);

//C# TO C++ CONVERTER NOTE: The following 'using' block is replaced by its C++ equivalent:
//ORIGINAL LINE: using (var stream = Surface.ToStream(backbuffer, ImageFileFormat.Png))
        {
            auto stream = Surface::ToStream(backbuffer, ImageFileFormat::Png);
            Bitmap *image = new Bitmap(stream);

//C# TO C++ CONVERTER NOTE: The following 'using' block is replaced by its C++ equivalent:
//ORIGINAL LINE: using (Graphics graphics = Graphics.FromImage(image))
            {
                Graphics graphics = Graphics->FromImage(image);
                StringFormat *sf = new StringFormat();
                sf->LineAlignment = StringAlignment::Center;
                sf->Alignment = StringAlignment::Center;

                System::Drawing::Font tempVar(Settings::FontName, 9.0F);
                Point tempVar2((Settings::ScreenWidth / 2) + 3, 10);
                graphics.DrawString(text, &tempVar, Brushes::Black, &tempVar2, sf);
                System::Drawing::Font tempVar3(Settings::FontName, 9.0F);
                Point tempVar4((Settings::ScreenWidth / 2) + 4, 9);
                graphics.DrawString(text, &tempVar3, Brushes::Black, &tempVar4, sf);
                System::Drawing::Font tempVar5(Settings::FontName, 9.0F);
                Point tempVar6((Settings::ScreenWidth / 2) + 5, 10);
                graphics.DrawString(text, &tempVar5, Brushes::Black, &tempVar6, sf);
                System::Drawing::Font tempVar7(Settings::FontName, 9.0F);
                Point tempVar8((Settings::ScreenWidth / 2) + 4, 11);
                graphics.DrawString(text, &tempVar7, Brushes::Black, &tempVar8, sf);
                System::Drawing::Font tempVar9(Settings::FontName, 9.0F);
                Point tempVar10((Settings::ScreenWidth / 2) + 4, 10);
                graphics.DrawString(text, &tempVar9, Brushes::White, &tempVar10, sf); //SandyBrown

                std::string path = FileSystem::combine(Application::StartupPath, R"(Screenshots\)");
                if (!FileSystem::directoryExists(path))
                {
                    FileSystem::createDirectory(path);
                }

                int count = Directory::GetFiles(path, "*.png").size();

                image->Save(FileSystem::combine(path, StringHelper::formatSimple("Image {0}.png", count)), ImageFormat::Png);

//C# TO C++ CONVERTER TODO TASK: A 'delete sf' statement was not added since sf was passed to a method or constructor. Handle memory management manually.
            }

//C# TO C++ CONVERTER TODO TASK: A 'delete image' statement was not added since image was passed to a method or constructor. Handle memory management manually.
        }
    }

    void CMain::SaveError(const std::string &ex)
    {
        try
        {
            if (Settings::RemainingErrorLogs-- > 0)
            {
                File::AppendAllText(R"(.\Error.txt)", StringHelper::formatSimple("[{0}] {1}{2}", getNow(), ex, "\r\n"));
            }
        }
        catch (...)
        {
        }
    }

    void CMain::SetResolution(int width, int height)
    {
        if (Settings::ScreenWidth == width && Settings::ScreenHeight == height)
        {
            return;
        }

        Settings::ScreenWidth = width;
        Settings::ScreenHeight = height;
        Program::Form->ClientSize = new Size(width, height);

        DXManager::Device->Clear(ClearFlags::Target, Color::Black, 0, 0);
        DXManager::Device->Present();
        DXManager::ResetDevice();

        Program::Form->CenterToScreen();
    }

    bool CMain::getAppStillIdle()
    {
        PeekMsg msg;
        return !PeekMessage(msg, 0, 0, 0, 0);
    }

    void CMain::CMain_FormClosing(std::any sender, FormClosingEventArgs *e)
    {
        if (CMain::Time < GameScene::LogTime && !Settings::getUseTestConfig())
        {
            GameScene::Scene->ChatDialog->ReceiveChat(std::string::Format(GameLanguage::CannotLeaveGame, (GameScene::LogTime - CMain::Time) / 1000), ChatType::System);
            e->Cancel = true;
        }
    }

    void CMain::WndProc(Message *&m)
    {
        if (m->Msg == 0x0112) // WM_SYSCOMMAND
        {
            if (m->WParam.ToInt32() == 0xF100) // SC_KEYMENU
            {
                m->Result = 0;
                return;
            }
            else if (m->WParam.ToInt32() == 0xF030) // SC_MAXIMISE
            {
                ToggleFullScreen();
                return;
            }
        }

        RenderForm::WndProc(m);
    }

std::vector<Cursor*> CMain::Cursors;
MouseCursor CMain::CurrentCursor = MouseCursor::None;

    void CMain::SetMouseCursor(MouseCursor cursor)
    {
        if (!Settings::UseMouseCursors)
        {
            return;
        }

        if (CurrentCursor != cursor)
        {
            CurrentCursor = cursor;
            Program::Form->Cursor = Cursors[static_cast<unsigned char>(cursor)];
        }
    }

    void CMain::LoadMouseCursors()
    {
        Cursors = std::vector<Cursor*>(8);

        Cursors[static_cast<int>(MouseCursor::None)] = Program::Form->Cursor;

        std::string path = StringHelper::formatSimple("{0}Cursor_Default.CUR", Settings::MouseCursorPath);
        if (FileSystem::fileExists(path))
        {
            Cursors[static_cast<int>(MouseCursor::Default)] = LoadCustomCursor(path);
        }

        path = StringHelper::formatSimple("{0}Cursor_Normal_Atk.CUR", Settings::MouseCursorPath);
        if (FileSystem::fileExists(path))
        {
            Cursors[static_cast<int>(MouseCursor::Attack)] = LoadCustomCursor(path);
        }

        path = StringHelper::formatSimple("{0}Cursor_Compulsion_Atk.CUR", Settings::MouseCursorPath);
        if (FileSystem::fileExists(path))
        {
            Cursors[static_cast<int>(MouseCursor::AttackRed)] = LoadCustomCursor(path);
        }

        path = StringHelper::formatSimple("{0}Cursor_Npc.CUR", Settings::MouseCursorPath);
        if (FileSystem::fileExists(path))
        {
            Cursors[static_cast<int>(MouseCursor::NPCTalk)] = LoadCustomCursor(path);
        }

        path = StringHelper::formatSimple("{0}Cursor_TextPrompt.CUR", Settings::MouseCursorPath);
        if (FileSystem::fileExists(path))
        {
            Cursors[static_cast<int>(MouseCursor::TextPrompt)] = LoadCustomCursor(path);
        }

        path = StringHelper::formatSimple("{0}Cursor_Trash.CUR", Settings::MouseCursorPath);
        if (FileSystem::fileExists(path))
        {
            Cursors[static_cast<int>(MouseCursor::Trash)] = LoadCustomCursor(path);
        }

        path = StringHelper::formatSimple("{0}Cursor_Upgrade.CUR", Settings::MouseCursorPath);
        if (FileSystem::fileExists(path))
        {
            Cursors[static_cast<int>(MouseCursor::Upgrade)] = LoadCustomCursor(path);
        }
    }

    Cursor *CMain::LoadCustomCursor(const std::string &path)
    {
        std::intptr_t hCurs = LoadCursorFromFile(path);
        if (hCurs == 0)
        {
            throw Win32Exception();
        }
        auto curs = new Cursor(hCurs);
        // Note: force the cursor to own the handle so it gets released properly
//C# TO C++ CONVERTER TODO TASK: There is no C++ equivalent to the C# 'typeof' operator:
        auto fi = typeof(Cursor)->GetField("ownHandle", BindingFlags::NonPublic | BindingFlags::Instance);
        fi->SetValue(curs, true);

//C# TO C++ CONVERTER TODO TASK: A 'delete curs' statement was not added since curs was passed to a method or constructor. Handle memory management manually.
        return curs;
    }

    void CMain::Dispose(bool disposing)
    {
        if (disposing && (components != nullptr))
        {
            components->Dispose();
        }
        RenderForm::Dispose(disposing);
    }

    void CMain::InitializeComponent()
    {
//C# TO C++ CONVERTER TODO TASK: There is no C++ equivalent to the C# 'typeof' operator:
        System::ComponentModel::ComponentResourceManager *resources = new System::ComponentModel::ComponentResourceManager(typeof(CMain));
        this->SuspendLayout();
        // 
        // CMain
        // 
        this->AutoScaleDimensions = new System::Drawing::SizeF(6.0F, 13.0F);
        this->AutoScaleMode = System::Windows::Forms::AutoScaleMode::Font;
        this->BackColor = System::Drawing::Color::Black;
        this->ClientSize = new System::Drawing::Size(275, 260);
        this->FormBorderStyle = System::Windows::Forms::FormBorderStyle::FixedSingle;
        this->Icon = (std::any_cast<System::Drawing::Icon*>(resources->GetObject("$this.Icon")));
        this->MinimumSize = new System::Drawing::Size(200, 213);
        this->Name = "CMain";
        this->Text = "Legend of Mir";
        this->FormClosing += new System::Windows::Forms::FormClosingEventHandler(this->CMain_FormClosing);
        this->Load += new System::EventHandler(this->CMain_Load);
        this->ResumeLayout(false);

        delete resources;
    }
}
